/*
 * Copyright (c) 2025 Sailing
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */
#include "stdio.h"
#include "stdbool.h"
#include "jedec_nand_driver.h"

jedec_nand_handle_t nand_handle;
Nand_Parameter_Page_t Nand_Parameter_Data;
uint8_t READ_ID(jedec_nand_handle_t* jedec_handle)
{
    uint8_t ID[3];
    uint8_t cmd_read_id = READ_ID_CMD;
    jedec_handle->spi_function(&cmd_read_id,ID,1,2,1);
    return true;
}

uint8_t Get_Status_Register(jedec_nand_handle_t *jedec_handle,uint8_t status_reg_addr)
{
    uint8_t cmd_sequence[2] = {GET_FEATURE_CMD,status_reg_addr};
    uint8_t recive_data = 0;
    jedec_handle->spi_function(cmd_sequence, &recive_data,2,1,0);
    return recive_data;
}

uint8_t Set_Status_Register(jedec_nand_handle_t *jedec_handle,uint8_t status_reg_addr,uint8_t status_data)
{
    uint8_t cmd_sequence[3] = {SET_FEATURE_CMD,status_reg_addr,status_data};
    jedec_handle->spi_function(cmd_sequence,NULL,sizeof(cmd_sequence),0,0);
    return true;
} 

uint32_t Nand_Flash_Read(jedec_nand_handle_t *jedec_handle,uint16_t block,uint16_t page,uint16_t col,uint8_t* buf,uint16_t len)
{
    uint32_t ui32Addr = (block << 6) + page;	
    uint8_t read_page_to_cache[4] = {0};
    uint8_t read_from_cache[3] = {0};
    uint8_t status = 0;
    uint16_t loop_times = 0;
    read_page_to_cache[0] = READ_TO_CACHE_CMD;
    read_page_to_cache[1] = (uint8_t)(ui32Addr >> 16);
    read_page_to_cache[2] = (uint8_t)(ui32Addr >> 8);
    read_page_to_cache[3] = (uint8_t)ui32Addr;


    jedec_handle->spi_function(read_page_to_cache,NULL,sizeof(read_page_to_cache),0,0);

    while(1){
        status = Get_Status_Register(jedec_handle,ADDR_REG_STATUS);/* 查看写到缓冲区的内容是否正确 */
        if((status&0x01) == 0)
        {
            break;
        }
        loop_times++;
        if(loop_times >500)
        {
            printf("Nand read page to cache failed\r\n");
            return false;
        }
    }

     read_from_cache[0] = READ_FROM_CACHE_CMD;
     read_from_cache[1] = (col & 0xFF00)>>8;
     read_from_cache[2] = col&0xff;

     jedec_handle->spi_function(read_from_cache,buf,sizeof(read_page_to_cache),len,1);
}
uint8_t Read_Parameter_Page(jedec_nand_handle_t *jedec_handle,uint8_t* parameter_page)
{
    uint8_t ret = 0;
    uint8_t Parameter_Page_Signature[3] = {0x4E,0x46,0x49};
    Set_Status_Register(jedec_handle,ADDR_REG_FEATURE,0x40);
    
    ret = Get_Status_Register(jedec_handle, ADDR_REG_FEATURE);
    
    for(uint16_t i = 0;i<16;i++)
    {
        Nand_Flash_Read(jedec_handle,0,i,0,parameter_page,sizeof(Nand_Parameter_Page_t));
        if(Nand_Parameter_Data.Parameter_Page_Signature == 0x49464E4F)
        {
            break;
        }
        if (i == 15) {
            printf("Device unsupport JEDEC\r\n");
        }
    }
    
    return true;
}



uint8_t init_jedec_nand_handle(jedec_nand_handle_t *jedec_handle , void* spi_function)
{
    jedec_handle->spi_function = spi_function;

    READ_ID(jedec_handle);

    Read_Parameter_Page(jedec_handle,(uint8_t*)&Nand_Parameter_Data);
    jedec_handle->lun_num = Nand_Parameter_Data.Lun_Num;
    jedec_handle->Block_Total_Num = (Nand_Parameter_Data.Block_Num_Per_Lun) * (jedec_handle->lun_num);
    jedec_handle->Block_Page_Num = Nand_Parameter_Data.Page_Num_Per_Block;
    jedec_handle->Data_Area_Size = Nand_Parameter_Data.Page_Data_Size;
    jedec_handle->Spare_Area_Size = Nand_Parameter_Data.Page_Spare_Size;

    printf("\r\n\r\nNAND FLASH Info :\r\n");
    printf("Device manufacturer :     %.12s\r\n",Nand_Parameter_Data.Device_Manufacturer);
    printf("Device Model :            %.20s\r\n",Nand_Parameter_Data.Device_Model);
    printf("Device Lun Number :       %d\r\n",jedec_handle->lun_num);
    printf("Device Block Number :     %d\r\n",jedec_handle->Block_Total_Num);
    printf("Page number per Block :   %d\r\n",jedec_handle->Block_Page_Num);
    printf("Page Data area size :     %d Byte\r\n",jedec_handle->Data_Area_Size);
    printf("Page Spare area size :    %d Byte\r\n",jedec_handle->Spare_Area_Size);
    printf("Total capacity :          %dMB",(jedec_handle->Block_Total_Num)*(jedec_handle->Data_Area_Size)*(jedec_handle->Block_Page_Num)/(1024*1024));
    return true;
}


void test_Nand(void)
{
    
}
